package org.bud.db.dynamic.base;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.util.ReflectionUtils;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Objects;

/**
 * @author shaun
 * @date 2025/4/1
 * @instruction
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    public DynamicDataSource(){}
    public DynamicDataSource(Map<Object, Object> targetDataSources, Object defaultTargetDataSource){
        this.setDefaultTargetDataSource(defaultTargetDataSource);
        this.setTargetDataSources(targetDataSources);
    }
    @Override
    protected Object determineCurrentLookupKey() {
        try {
            return DynamicDataSourceHolder.get();
        } catch (Exception e){
            return this.getDefaultDataSourceLookKey();
       }
    }

    public Object getDefaultDataSourceLookKey(){
        Map<Object, DataSource> resolvedDataSources = getResolvedDataSources(this);
        for(Object key : resolvedDataSources.keySet()){
            DataSource dataSource = resolvedDataSources.get(key);
            if(Objects.nonNull(dataSource)){
                if(dataSource instanceof DynamicVSource){
                    if(((DynamicVSource) dataSource).isDefaultDb()){
                        return key;
                    }
                }
            }
        }
        throw new IllegalArgumentException("check the Dynamic data source config,has something wrong");
    }

    public Map<Object, DataSource> getResolvedDataSources(Object $this){
        Field field = ReflectionUtils.findField($this.getClass(), "resolvedDataSources");
        ReflectionUtils.makeAccessible(field);
        return (Map<Object, DataSource>)ReflectionUtils.getField(field,$this);
    }

    public DataSource getResolvedDefaultDataSource(Object $this){
        Field field = ReflectionUtils.findField($this.getClass(), "resolvedDefaultDataSource");
        ReflectionUtils.makeAccessible(field);
        return (DataSource)ReflectionUtils.getField(field,$this);
    }
}